/*──────────────────────────────────────────────────────────────────────────────┐
│Copyright 2024 Zhengyang Zhong (zhengyangz99@163.com)                          │
│                                                                               │
│Permission is hereby granted, free of charge, to any person obtaining a copy   │
│of this software and associated documentation files (the "Software"), to deal  │
│in the Software without restriction, including without limitation the rights   │
│to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      │
│copies of the Software, and to permit persons to whom the Software is furnished│
│to do so, subject to the following conditions:                                 │
│                                                                               │
│The above copyright notice and this permission notice shall be included in all │
│copies or substantial portions of the Software.                                │
│                                                                               │
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     │
│IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       │
│FINIESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    │
│AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER.        │
│LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  │
│OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  │
│SOFTWARE.                                                                      │
└──────────────────────────────────────────────────────────────────────────────*/

#ifndef OPENGLLINEWIDGET_H
#define OPENGLLINEWIDGET_H

#include <cmath>
#include <random>
#include <string>
#include <algorithm> 

#include <QPainter>
#include <QVector3D>
#include <QMouseEvent>
#include <QQuaternion>
#include <QBasicTimer>
#include <QOpenGLWidget>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>

#include "trackData.h"

// Used to show text in an image texture
const float labelUVs[] = {
	0.0f, 1.0f,  // 左上角
	0.0f, 0.0f,	 // 左下角
	1.0f, 1.0f,	 // 右上角
	1.0f, 0.0f	 // 右下角
};

class Q3DLineGraphWidget : public QOpenGLWidget, protected QOpenGLFunctions{
    Q_OBJECT

public:

	explicit Q3DLineGraphWidget(QWidget *parent = nullptr,
								int h = 0, int w = 0);
	~Q3DLineGraphWidget();

	// Input data 
	int maxHeight = 0;
	int maxWidth = 0;
	void setData(const std::vector<trackingData>& data);

	// Setup colors
	void setRandomColor();
	void setTickColor(QVector3D color);
	void setAxisColor(QVector3D color);
	QVector3D highlightColor = QVector3D(1.0f, 1.0f, 1.0f);
	void setHighlightColor(QVector3D color);
	void setTrajectoryColor(QVector3D color);
	void setObjectPointColor(QVector3D color);
	void setEventColor(QVector3D beforeEvent, QVector3D afterEvent);

	// Setup axes   
	void setPointSize(float size);
	void setTickNum(int num);
	void setGeneralLabelSize(float textHeight);
	void setAxisLabelSize(float textHeight);
	void setTickLabelSize(float textHeight);
	void showZTicks();
	void showXLabel(std::string label);
	void showYLabel(std::string label);
	void showZLabel(std::string label);
	void showZTickLabels();

	// Setup mesh grid
	void showMeshGrid(int xMeshNum, int yMeshNum);
	void showXMeshLine(int xMeshNum);
	void showYMeshLine(int yMeshNum);

	// Setup text
	void setFontSize(int size);
	void setFontType(QString name);
	void setFontColor(QColor color);
    void setTextPadding(int padding);
	void highlightData(int hlId);
									

public slots:
	void cleanup();
	
protected:
    
	void initializeGL() override;
	void resizeGL(int width, int height) override;
	void paintGL() override;

	void mousePressEvent(QMouseEvent *e) override;
	void mouseReleaseEvent(QMouseEvent *e) override;
	void timerEvent(QTimerEvent *e) override;

private:
	// Store data
	std::vector<trackingData> tds;
	void rescalePosition();	

	// Setup OpenGL
	QOpenGLFunctions *function;
	// interactive rotation
	QBasicTimer timer;
	QQuaternion rotation;
	QVector3D rotationAxis;
	qreal angularSpeed = 0.0;
	float arrowRadius = 0.005f;
	QVector2D mousePressPosition;
	// render elements and text
	QOpenGLShaderProgram *textRenderProgram = nullptr;
	QOpenGLShaderProgram *elementRenderProgram = nullptr;
	// project 3D objects to 2D screen
	QMatrix4x4 projection;
	QMatrix4x4 viewMatrix;
	QMatrix4x4 modelMatrix;
	// show elements, including points, lines and arrows
	QOpenGLBuffer posVBO;
	QOpenGLBuffer colorVBO;
	QOpenGLVertexArrayObject elementVAO;
	// show text, including labels and numbers
	QOpenGLBuffer textUVVBO;
	QOpenGLBuffer textArrayVBO;
	QOpenGLVertexArrayObject textVAO;
	QOpenGLTexture *texture = nullptr;
	// initialize shader in overrided func initializeGL
	void initializeTextShaderProgram();
	void initializeElementShaderProgram();

	// axes
	int zMax = 0;
	int tickNum = 5;
	float pointSize = 3.0f;
	float axisLength = 0.5f;
	// text
	int fontSize = 14;
	int textPadding = 10;
	int textureWidth = 0;
	int textureHeight = 0;
	float axisLabelSize = 0.05f;
	float tickLabelSize = 0.02f;
	QString fontName = "Arial";
	QColor fontColor = Qt::white;
	QVector3D axisOfRotation = QVector3D(0.25f, 0.25f, 0.0f);
	// colors
	enum colorMode {
		NORMAL, RANDOM, BYEVENT
	};
	colorMode presentColorMode = NORMAL;
	QVector3D tickColor = QVector3D(0.5f, 0.5f, 0.5f);
	QVector3D axisColor = QVector3D(1.0f, 1.0f, 1.0f);
	QVector3D trajectoryColor = QVector3D(1.0f, 1.0f, 1.0f);
	QVector3D objectPointColor = QVector3D(1.0f, 1.0f, 1.0f);
	QVector3D beforeEventColor = QVector3D(1.0f, 1.0f, 1.0f);
	QVector3D afterEventColor = QVector3D(1.0f, 1.0f, 1.0f);
	// Draw elements and texts
	void showAxes();
	void showArrows();
	void showOrigin();
	void showTrajectories();
	void createTextTexture(QString label);
	void passTextDataToVAO(GLfloat labelVertices[]);
	void passElementDataToVAO(const float *vertices, const float *colors, int verticesNum);
	
	// Debug
	GLenum errorCode;
	void checkError();
};
#endif
